package com.zhengming.juc;

public class T02_03_GetInstance {

    private static volatile T02_03_GetInstance INSTANCE;

    private T02_03_GetInstance() {}

    public static T02_03_GetInstance getInstance() {
        if (INSTANCE == null) {
//            try {
//                Thread.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            INSTANCE = new T02_03_GetInstance();
            // 代码块加锁
//            synchronized (T02_03_GetInstance.class) {
//                try {
//                    Thread.sleep(1);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                INSTANCE = new T02_03_GetInstance();
//            }
            /**
             * DCL: double check lock,检查两遍锁
             *      第一次检测在第10行，每个线程进来都需要判断当前实例是否存在，有即返回。（有坑:指令重排序）
             *      第二次检测在本次代加锁的代码块内部，判断当前实例是否存在
             *      目的： 上面注释代码属于一重锁，在第一个线程进来判断为空之后获取到当前代码块的锁正在生成一个新的实例，
             *              这时候其他多个线程进来也进来了，只不过因为当前代码块的锁已经被第一个线程占有
             *              其他线程无法继续下去，只能继续等待锁的释放，但是他们都已经过了非空判断，他们获得锁
             *              之后的行为都是生成一个新的实例，所以在下面的代码中，加入了第二重非空判断，以表示其他线程
             *              获得锁之后，生成实例之前会再一次判断在获得锁之前这个实例有没有生成。
              */
            synchronized (T02_03_GetInstance.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new T02_03_GetInstance();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(T02_03_GetInstance.getInstance().hashCode());
            }).start();
        }
    }

}
